﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
using BL;
using Common;
using DAL.Model;
using DevExpress.XtraEditors;
using DevExpress.XtraGrid.Views.Base;
using DevExpress.XtraGrid.Views.Grid;
using UI.Helper;

namespace UI.MainFunctions
{
    public partial class frmStockOut : Base.DialogViewBase
    {
        #region Private variables

        private MasterSession _session;
        private BindingList<StockOutDetail> _stockOutDetails;
        private StockOutController _stockOutController;
        private readonly Transfer[] _transfers;
        private UnitOfMeasure[] _unitOfMeasures;
        private readonly FormAction _action;
        private StockOut _stockOut;
        private readonly int _stockOutId;
        private Product[] _products;
        private Customer[] _customers;

        #endregion

        #region Constructor

        public frmStockOut()
        {
            InitializeComponent();
        }

        public frmStockOut(Transfer[] transfers, FormAction action)
            : this()
        {
            _transfers = transfers;
            _action = action;
        }

        public frmStockOut(int stockOutId, FormAction action)
            : this()
        {
            _stockOutId = stockOutId;
            _action = action;
        }

        public frmStockOut(StockOut stockOut, FormAction action, MasterSession session)
            : this()
        {
            _stockOut = stockOut;
            _action = action;
            _session = session;
        }

        #endregion

        #region Overided methods

        protected override void InitializeBO()
        {
            base.InitializeBO();

            if (_session == null)
            {
                _session = new MasterSession();
            }
            _stockOutController = new StockOutController(_session);
        }

        protected override void PopulateStaticData()
        {
            base.PopulateStaticData();
            LoadCustomers();
            LoadUoms();
        }

        protected override void PopulateData()
        {
            base.PopulateData();
            if (_action != FormAction.New && _stockOut == null)
            {
                _stockOut = _session.StockOuts.FirstOrDefault(t => t.Id == _stockOutId);
            }
            _stockOutDetails =
                new BindingList<StockOutDetail>(_stockOut != null
                                                    ? _stockOut.StockOutDetails.ToList()
                                                    : new List<StockOutDetail>());
            dgStockOutDetail.DataSource = _stockOutDetails;
            gvStockOutDetail.BestFitColumns();

            BindingData();
            LoadProducts();
            switch (_action)
            {
                case FormAction.View:
                    DisableEditor();
                    break;
            }
        }

        protected override void FormatPrecision()
        {
            PrecisionHelper.FormatCurencyPrecision(gcMassQuantity,
                                                   gcQuantity,
                                                   gcUnitPrice,
                                                   gcSubTotal,
                                                   gcStockInQuantity,
                                                   gcDiscount);
        }

        #endregion

        #region Private methods

        private void LoadCustomers()
        {
            _customers = _session.Customers.ToArray();
            lueCustomers.Properties.DataSource = _customers;
            lueCustomers2.Properties.DataSource = _customers;
        }

        private void LoadUoms()
        {
            _unitOfMeasures = _session.UnitOfMeasures.ToArray();
            lueUOM.DataSource = _unitOfMeasures;
        }

        private void LoadProducts()
        {
            if (_stockOut != null && _stockOut.StockOutDetails.Count > 0)
            {
                _products = _stockOut.StockOutDetails
                    .GroupBy(t => t.Product)
                    .Select(t => t.Key)
                    .ToArray();
            }
            else
            {
                _products = _transfers
                    .SelectMany(t => t.TransferDetails)
                    .GroupBy(t => t.Product)
                    .Select(t => t.Key)
                    .ToArray();
            }
            lueProduct.DataSource = _products;
        }

        private void DisableEditor()
        {
            txtDocumentNo.Properties.ReadOnly = true;
            deStockedDate.Properties.ReadOnly = true;
            //lueCustomers.Properties.ReadOnly = true;
            gvStockOutDetail.OptionsBehavior.Editable = false;
            spSave.Enabled = false;
        }

        private void BindingData()
        {
            txtDocumentNo.DataBindings.Add("Text", _stockOut, "DocumentNo");
            deStockedDate.DataBindings.Add("EditValue", _stockOut, "StockedDate");
            lueCustomers.DataBindings.Add("EditValue", _stockOut, "CustomerId");
            lueCustomers2.DataBindings.Add("EditValue", _stockOut, "Customer2Id");
        }

        private bool ValidateData()
        {
            var validated = true;

            if (string.IsNullOrEmpty(_stockOut.DocumentNo))
            {
                txtDocumentNo.ErrorText = "Nhập số phiếu.";
                validated = false;
            }
            else
            {
                txtDocumentNo.ErrorText = string.Empty;
            }

            if (!CommonHelper.IsValidDate(_stockOut.StockedDate))
            {
                deStockedDate.ErrorText = "Ngày xuất không hợp lệ.";
                validated = false;
            }
            else
            {
                deStockedDate.ErrorText = string.Empty;
            }

            if (txtDocumentNo.ErrorText != string.Empty)
            {
                return validated;
            }

            if (!_stockOut.StockOutDetails.Any())
            {
                txtDocumentNo.ErrorText = "Nhập chi tiết hàng hóa.";
                validated = false;
            }
            else
            {
                txtDocumentNo.ErrorText = string.Empty;
            }

            var detail = _session.StockOuts
                .FirstOrDefault(t => t.Id != _stockOut.Id &&
                                     t.DocumentNo == _stockOut.DocumentNo);
            if (detail != null && _stockOut.Id != detail.Id)
            {
                txtDocumentNo.ErrorText = "Mã phiếu đã tồn tại";
                validated = false;
            }
            else
            {
                txtDocumentNo.ErrorText = string.Empty;
            }

            //if (_stockOutDetails.ToList()
            //    .Any(t => t.MassQuantity == 0 && t.Quantity == 0 && t.Amount == 0))
            //{
            //    MessageBox.Show("Tồn tại hàng xuất có khối lượng hoặc tiền bằng 0.");
            //    validated = false;
            //}

            return validated;
        }

        private int? GetNextLineNo()
        {
            var lineNo = _stockOutDetails.Max(t => t.LineNo);
            var nextLineNo = lineNo != null ? lineNo + 1 : 1;
            return nextLineNo;
        }

        #endregion

        private void spCancel_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void spSave_Click(object sender, EventArgs e)
        {
            if (!ValidateData())
            {
                return;
            }

            _stockOutController.PrepareSavingData(_stockOut);
            _session.CommitChanges();
            Close();
        }

        private void repositoryItemSpinEdit5_EditValueChanged(object sender, EventArgs e)
        {
            var spinEdit = sender as SpinEdit;
            // if not select product yet
            if (spinEdit == null || spinEdit.EditValue == null)
            {
                return;
            }

            var stockOutDetail = (StockOutDetail) gvStockOutDetail.GetRow(gvStockOutDetail.FocusedRowHandle);
            // if cannot get current row
            if (stockOutDetail == null)
            {
                return;
            }

            stockOutDetail.Amount = stockOutDetail.MassQuantity == 0
                                        ? stockOutDetail.Quantity
                                        : stockOutDetail.MassQuantity
                                          *stockOutDetail.Price;
        }

        private void speAmount_Enter(object sender, EventArgs e)
        {
            var spinEdit = sender as SpinEdit;
            // if not select product yet
            if (spinEdit == null || spinEdit.EditValue == null)
            {
                return;
            }

            var stockOutDetail = (StockOutDetail) gvStockOutDetail.GetRow(gvStockOutDetail.FocusedRowHandle);
            // if cannot get current row
            if (stockOutDetail == null)
            {
                return;
            }
            spinEdit.Enabled = stockOutDetail.MassQuantity == 0 ||
                               stockOutDetail.Quantity == 0;
        }

        private void lueProduct_EditValueChanged(object sender, EventArgs e)
        {
            var lookUpEdit = sender as LookUpEdit;
            // if not select product yet
            if (lookUpEdit == null || lookUpEdit.EditValue == null)
            {
                return;
            }

            var stockOutDetail = (StockOutDetail) gvStockOutDetail.GetRow(gvStockOutDetail.FocusedRowHandle);
            // if cannot get current row
            if (stockOutDetail == null)
            {
                return;
            }

            var product = _products.FirstOrDefault(t => t.Id == (int) lookUpEdit.EditValue);
            if (product == null)
            {
                return;
            }
            stockOutDetail.Product = product;
            stockOutDetail.ProductId = product.Id;

            var detail = _stockOutDetails
                .FirstOrDefault(t => t.ProductId == (int) lookUpEdit.EditValue);
            if (detail == null)
            {
                return;
            }
            stockOutDetail.StockInQuantity = detail.StockInQuantity;
            stockOutDetail.TransferDetail = detail.TransferDetail;
        }

        private void gvStockOutDetail_InitNewRow(object sender, InitNewRowEventArgs e)
        {
            var stockOutDetail = (StockOutDetail) gvStockOutDetail.GetRow(gvStockOutDetail.FocusedRowHandle);
            if (stockOutDetail == null)
            {
                return;
            }
            stockOutDetail.LineNo = GetNextLineNo();
            stockOutDetail.StockOut = _stockOut;
            _stockOut.StockOutDetails.Add(stockOutDetail);
        }

        private void lueUOM_EditValueChanged(object sender, EventArgs e)
        {
            var lookUpEdit = sender as LookUpEdit;
            // if not select product yet
            if (lookUpEdit == null || lookUpEdit.EditValue == null)
            {
                return;
            }

            var stockOutDetail = (StockOutDetail) gvStockOutDetail.GetRow(gvStockOutDetail.FocusedRowHandle);
            // if cannot get current row
            if (stockOutDetail == null)
            {
                return;
            }

            var unitOfMeasure = _unitOfMeasures
                .FirstOrDefault(t => t.Id == (int) lookUpEdit.EditValue);
            stockOutDetail.UnitOfMeasure = unitOfMeasure;
        }

        private void gvStockOutDetail_ValidateRow(object sender, ValidateRowEventArgs e)
        {
            var stockOutDetail = (StockOutDetail) gvStockOutDetail.GetRow(gvStockOutDetail.FocusedRowHandle);
            // if cannot get current row
            if (stockOutDetail == null)
            {
                return;
            }

            gvStockOutDetail.ClearColumnErrors();

            if (stockOutDetail.Product == null)
            {
                gvStockOutDetail.SetColumnError(FormHelper.GetColumn(gvStockOutDetail, "Product.Id"), "Chọn sản phẩm");
                e.Valid = false;
            }
            if (stockOutDetail.StockInQuantity < 0)
            {
                gvStockOutDetail.SetColumnError(FormHelper.GetColumn(gvStockOutDetail, "StockInQuantity"),
                                                "Số lượng nhập không hợp lệ");
                e.Valid = false;
            }
            if (string.IsNullOrEmpty(stockOutDetail.Specifical))
            {
                gvStockOutDetail.SetColumnError(FormHelper.GetColumn(gvStockOutDetail, "Specifical"), "Nhập quy cách");
                e.Valid = false;
            }
            //if (stockOutDetail.MassQuantity < 0)
            //{
            //    gvStockOutDetail.SetColumnError(FormHelper.GetColumn(gvStockOutDetail, "MassQuantity"), "Khối lượng không hợp lệ");
            //    e.Valid = false;
            //}
            if (stockOutDetail.Quantity < 0)
            {
                gvStockOutDetail.SetColumnError(FormHelper.GetColumn(gvStockOutDetail, "Quantity"),
                                                "Số lượng không hợp lệ");
                e.Valid = false;
            }
            //if (stockOutDetail.UnitOfMeasure == null)
            //{
            //    gvStockOutDetail.SetColumnError(FormHelper.GetColumn(gvStockOutDetail, "UnitOfMeasure.Id"), "Chọn đơn vị");
            //    e.Valid = false;
            //}
            if (stockOutDetail.Price < 0)
            {
                gvStockOutDetail.SetColumnError(FormHelper.GetColumn(gvStockOutDetail, "Price"), "Đơn giá không hợp lệ");
                e.Valid = false;
            }
            //if (stockOutDetail.Amount < 0)
            //{
            //    gvStockOutDetail.SetColumnError(FormHelper.GetColumn(gvStockOutDetail, "Amount"), "Tổng tiền không hợp lệ");
            //    e.Valid = false;
            //}
        }

        private void gvStockOutDetail_InvalidRowException(object sender, InvalidRowExceptionEventArgs e)
        {
            e.ExceptionMode = DevExpress.XtraEditors.Controls.ExceptionMode.NoAction;
        }

        private void gvStockOutDetail_KeyDown(object sender, KeyEventArgs e)
        {
            StockOutDetail detail;
            var isNewItemRow = gvStockOutDetail.IsNewItemRow(gvStockOutDetail.FocusedRowHandle);
            switch (e.KeyData)
            {
                case Keys.Escape:
                    if (!isNewItemRow)
                    {
                        return;
                    }
                    detail = (StockOutDetail) gvStockOutDetail.GetRow(gvStockOutDetail.FocusedRowHandle);
                    if (detail == null)
                    {
                        return;
                    }
                    _session.StockOutDetails.Remove(detail);
                    break;
                case Keys.F2:
                    if (isNewItemRow)
                    {
                        return;
                    }
                    detail = (StockOutDetail) gvStockOutDetail.GetRow(gvStockOutDetail.FocusedRowHandle);
                    if (detail == null || detail.Product == null)
                    {
                        return;
                    }

                    var newDetail = _stockOutController.CreateDetail(_stockOut);
                    newDetail.LineNo = GetNextLineNo();
                    newDetail.Product = detail.Product;
                    newDetail.ProductId = detail.ProductId;
                    newDetail.Product.Code = detail.Product.Code;
                    newDetail.Product.Name = detail.Product.Name;
                    newDetail.Product.ProductCategory = detail.Product.ProductCategory;
                    newDetail.Product.ProductCategoryId = detail.Product.ProductCategoryId;
                    newDetail.UnitOfMeasure = detail.UnitOfMeasure;
                    newDetail.Quantity = detail.Quantity;
                    newDetail.MassQuantity = detail.MassQuantity;
                    newDetail.StockInQuantity = detail.StockInQuantity;
                    newDetail.TransferDetail = detail.TransferDetail;
                    _stockOutDetails.Add(newDetail);

                    break;
                case Keys.Delete:
                    if (isNewItemRow)
                    {
                        return;
                    }
                    if (_stockOut.StockOutDetails.Count == 1)
                    {
                        return;
                    }

                    if (DialogResult.No == MessageBox.Show("Bạn muốn xóa dòng đang chọn?",
                                                           "Xác nhận",
                                                           MessageBoxButtons.YesNo))
                    {
                        return;
                    }
                    detail = (StockOutDetail) gvStockOutDetail.GetRow(gvStockOutDetail.FocusedRowHandle);
                    _session.StockOutDetails.Remove(detail);
                    gvStockOutDetail.DeleteRow(gvStockOutDetail.FocusedRowHandle);
                    break;
                default:
                    return;
            }
        }

        private void gvStockOutDetail_CellValueChanged(object sender, CellValueChangedEventArgs e)
        {
            var stockOutDetail = (StockOutDetail) gvStockOutDetail.GetRow(gvStockOutDetail.FocusedRowHandle);
            // if cannot get current row
            if (stockOutDetail == null)
            {
                return;
            }

            if (stockOutDetail.MassQuantity + stockOutDetail.Quantity == 0)
            {
                return;
            }

            if (stockOutDetail.Price != 0)
            {
                stockOutDetail.Amount = (stockOutDetail.MassQuantity != 0
                                             ? stockOutDetail.MassQuantity
                                             : stockOutDetail.Quantity)
                                        *stockOutDetail.Price;
            }

            //if(stockOutDetail.IsAccumulated != null)
            //{
            //    // find next lineNo with specifical contains "keo"
            //    var lineNo = stockOutDetail.LineNo;
            //    var soKeo = _stockOutDetails
            //        .FirstOrDefault(t => Equals(t.LineNo, lineNo + 1) &&
            //                             t.Product.Id == stockOutDetail.Product.Id &&
            //                             t.Specifical.ToLower().Contains("keo"));
            //    if(soKeo == null)
            //    {
            //        return;
            //    }
            //    if((bool) stockOutDetail.IsAccumulated)
            //    {
            //        // Quy cach xuat nay da co keo, 
            //        // tim trong cac SO detail lay ra dong co chu 'keo'
            //        // lay so luong keo xuat nay tru voi so luong xuat cua quy cach
            //        soKeo.Accumulated = true;
            //        stockOutDetail.Amount -= (soKeo.MassQuantity == 0
            //                                      ? soKeo.Quantity
            //                                      : soKeo.MassQuantity) * soKeo.Price;
            //    }
            //    else
            //    {
            //        soKeo.Accumulated = false;
            //    }
            //}
            //if (!string.IsNullOrEmpty(stockOutDetail.Specifical) &&
            //    stockOutDetail.Specifical.ToLower().Contains("keo"))
            //{
            //    // find previous lineNo with checked "Da co keo"
            //    var lineNo = stockOutDetail.LineNo;
            //    var sodAccumulated = _stockOutDetails
            //        .FirstOrDefault(t => Equals(t.LineNo, lineNo - 1) &&
            //                             t.Product.Id == stockOutDetail.Product.Id &&
            //                             (t.IsAccumulated ?? false));
            //    if (sodAccumulated == null)
            //    {
            //        return;
            //    }
            //    sodAccumulated.Amount = (sodAccumulated.MassQuantity > 0
            //                                 ? sodAccumulated.MassQuantity
            //                                 : sodAccumulated.Quantity)
            //                            * sodAccumulated.Price -
            //                            stockOutDetail.Amount;
            //}

            // dont use this. that may cause show lacking data on form
            //gvStockOutDetail.RefreshData();
        }

        private void lueCustomers2_EditValueChanged(object sender, EventArgs e)
        {
            if (lueCustomers2.EditValue == null ||
                DBNull.Value.Equals(lueCustomers2.EditValue))
            {
                return;
            }
            var customer = _customers
                .FirstOrDefault(t => t.Id == (int) lueCustomers2.EditValue);
            if (customer == null)
            {
                return;
            }
            _stockOut.Customer2 = customer;
            _stockOut.Customer2Id = customer.Id;
        }

        /// <summary>
        /// Move up a line.
        /// </summary>
        private void simpleButton1_Click(object sender, EventArgs e)
        {
            // if the first line or new line
            if (gvStockOutDetail.FocusedRowHandle <= 0)
            {
                return;
            }

            // get current line no
            var detail = (StockOutDetail) gvStockOutDetail.GetRow(gvStockOutDetail.FocusedRowHandle);
            if (detail == null || detail.LineNo == 1)
            {
                return;
            }

            // get previous line no
            var prevDetail = (StockOutDetail) gvStockOutDetail.GetRow(gvStockOutDetail.FocusedRowHandle - 1);
            if (prevDetail == null || prevDetail.LineNo < 1)
            {
                return;
            }
            var lineNo = detail.LineNo;
            detail.LineNo = prevDetail.LineNo;
            prevDetail.LineNo = lineNo;

            gvStockOutDetail.RefreshData();
        }

        /// <summary>
        /// Move down a line.
        /// </summary>
        private void simpleButton2_Click(object sender, EventArgs e)
        {
            var maxLineNo = _stockOutDetails.Count;
            // if the last line
            if (gvStockOutDetail.FocusedRowHandle >= maxLineNo - 1)
            {
                return;
            }

            // get current line no
            var detail = (StockOutDetail) gvStockOutDetail.GetRow(gvStockOutDetail.FocusedRowHandle);
            if (detail == null || detail.LineNo >= maxLineNo)
            {
                return;
            }

            // get next line no
            var nextDetail = (StockOutDetail) gvStockOutDetail.GetRow(gvStockOutDetail.FocusedRowHandle + 1);
            if (nextDetail == null || nextDetail.LineNo > maxLineNo)
            {
                return;
            }

            var lineNo = detail.LineNo;
            detail.LineNo = nextDetail.LineNo;
            nextDetail.LineNo = lineNo;

            gvStockOutDetail.RefreshData();
        }
    }
}
